package com.guptarulie.jmeter.protocol.mm7.deliveryrequest.control;


import java.util.Date;
import java.util.Enumeration;
//import java.io.BufferedReader;
//import java.io.BufferedWriter;
import java.io.InputStream;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
//import java.io.IOException;
//import java.io.InputStreamReader;
//import java.io.OutputStreamWriter;
//import java.net.ServerSocket;
import java.net.Socket;


import javax.mail.internet.InternetHeaders;
//import javax.mail.MessagingException;

//import org.apache.jmeter.util.JMeterUtils;
import org.apache.jorphan.logging.LoggingManager;
import org.apache.jorphan.util.JOrphanUtils;
import org.apache.log.Logger;

import com.guptarulie.jmeter.protocol.mm7.deliveryrequest.control.gui.MM7DeliveryRequestReceiverControlGui;
/**
 * Thread to handle one client request. Gets the request from the client and
 * sends the response back to the client.
 */
public class MM7DeliveryRequestReceiverThread extends Thread {
    private static final Logger log = LoggingManager.getLoggerForClass();

    private static final String ISO_8859_1 = "ISO-8859-1"; //$NON-NLS-1$
    private static final String SUCCESS_CODE = "1000";
//    private static final byte[] CRLF = { 0x0d, 0x0a };
    private static MM7ConfigurableParameters mm7Parameters;
    private static long increment;

    /** Socket to client. */
    private final Socket clientSocket;
    
    // TODO When there would be multiple observers, we should use the Interface
    // observer class object here. Right now, can live this only :)
    private Object observerObject;
    
    // Buffer to hold the input socket stream
    private StringBuffer inputMsgBuffer;

    public MM7DeliveryRequestReceiverThread(Socket _clientSocket, MM7ConfigurableParameters parameters, Object obj) {
        this.clientSocket=_clientSocket;
        inputMsgBuffer = new StringBuffer();
        observerObject = obj;
        mm7Parameters = parameters;
    }

    /**
     * Main processing method for the MM7DeliveryRequestReceiverThread object
     */
    public void run()
    {
        log.info("Starting MM7DeliveryRequestReceiverThread");
        BufferedInputStream in = null;
        BufferedOutputStream out = null;

        try {
        	
        	InputStream inputStream = clientSocket.getInputStream();
        	in = new BufferedInputStream(inputStream);
            out = new BufferedOutputStream(clientSocket.getOutputStream());
            
        	// Call the View Update Method
            ((MM7DeliveryRequestReceiverControlGui)observerObject).udpateResultsPanel(false);

            // Print out the MM7 Parameters...
            mm7Parameters.printParameters();

            // Process the input stream and store it in local array. Then, fetch
            // the content type of the data.
    	    String contentType = processInputStream(inputStream);
    	    
            if( contentType.startsWith( "text/xml" ) )
            {
            	if (checkMessageType("DeliveryReportReq") || checkMessageType("ReadReplyReq")
            			|| checkMessageType("SubmitRsp"))
            	{
	            	// Delivery Report or Read Reply Report...DO NOTHING
	            	log.error("Thread must start with Delivery Request. No other messages are supported");
	            	return;
            	}
            	else
            	{
            		log.error("Unexpected message during start...Quitting the thread!");
            		return;
            	}
            }
            else if( contentType.startsWith( "multipart/related" ) )
            {
            	String transID = new String();
            	String linkedID = new String();
            	// Check if the message is Delivery Request or not
            	if (checkMessageType("SubmitReq"))
            	{
                   	// Parse the Delivery Request and fetch out the Transaction and Linked ID
                	transID = fetchInformationElementValue("TransactionID");
                	linkedID = fetchInformationElementValue("LinkedID");
                	
                	log.info("Successfully parsed the Delivery Request...Sending Delivery Response now...");
               	}
            	else
            	{
            		log.error("Unknown Message with Content Type - Multipart/Related");
            		return;
            	}
            	
            	// Send the Delivery Request response back to MMSC
            	sendDeliveryRequestResponse(out, transID);
            	
            	log.info("Successfully sent the Delivery Request response...");
            	            	
            	// Send the Submit Request to MMSC
            	log.info("Sending Submit Request now...");
            	sendSubmitRequest(out, linkedID);
            	
            	// Wait for the Submit Response and process it once it's received
            	if (processInputStream(inputStream).startsWith("text/xml"))
            	{
            		if (checkMessageType("SubmitRsp"))
                	{
                       	// Parse the Submit Response and fetch out the required parameters
                    	String statusCode = fetchInformationElementValue("StatusCode");
                    	String statusText = fetchInformationElementValue("StatusText");
                    	String messageID = new String();
                    	if (statusCode.equalsIgnoreCase(SUCCESS_CODE))
                    	{
                    		messageID = fetchInformationElementValue("MessageID");
                    	}
                    	else
                    	{
                    		log.error("Submit Request failed with error code: " + statusCode);
                    		log.error("Error Text: " + statusText);
                    		return;
                    	}
                    	log.info("Submit Resp is SUCCESSFULL with MessageID: " + messageID);

                    	// Call the View Update Method
                        ((MM7DeliveryRequestReceiverControlGui)observerObject).udpateResultsPanel(true);

                   	}
                	else
                	{
                		log.error("Unknown Message with Content Type - Multipart/Related");
                		return;
                	}
                		
            	}
            }
            else
                log.error("Unsupported Content Type...");
    	} 
        catch (Exception e)
    		{
    	    log.error("", e);
    	    }
        finally 
        {
            JOrphanUtils.closeQuietly(out);
            JOrphanUtils.closeQuietly(in);
            JOrphanUtils.closeQuietly(clientSocket);
        }
        log.info("End of MM7DeliveryRequestReceiverThread");
    }


    private String processInputStream(InputStream inStream)
    {
  	  inputMsgBuffer = new StringBuffer();
  	  String contentType = new String();
  		try {
  			InternetHeaders headers = new InternetHeaders( inStream );
  			Enumeration enumeration = headers.getAllHeaderLines();
  			
  			while( enumeration.hasMoreElements() )
  			{
  				inputMsgBuffer.append( ( String ) enumeration.nextElement() );
  				inputMsgBuffer.append( "\r\n" );
  			}
  			
  			inputMsgBuffer.append( "\r\n" );
  			
  			int contentLength = 0;
  			try {
  				String[] contentLengthStr = headers.getHeader( "content-length" );
  				if( contentLengthStr != null && contentLengthStr[0] != null )
  					contentLength = Integer.parseInt( contentLengthStr[0] );
  			} catch( NumberFormatException nfe ) {
  				log.error("", nfe);
  			}
  				
  			log.info("Content Length: " + contentLength);
  			if (contentLength == 0)
  			{
  				log.error("Content Length is 0. Quitting...");
  				return null;
  			}
  			
  			byte[] buf = new byte[4096];
  			int totalBytesRead = 0;
  			int bytesRead;
  			while( totalBytesRead < contentLength )
  			{
  				bytesRead = inStream.read( buf );
  				if(bytesRead == -1 ) 
  					break;
  				inputMsgBuffer.append( new String( buf, 0, bytesRead ) );
  				totalBytesRead += bytesRead;
  			}
  			log.info("Total bytes read:" + totalBytesRead);
  			
  			String contentTypes[] = headers.getHeader( "content-type" );
  			contentType = contentTypes[0];
  			
  			log.info("Content Type: " + contentType);
  			log.info("Input Message: " + inputMsgBuffer.toString());
  			
  		} catch (Exception except) {
  			except.printStackTrace();
  		}
  		return contentType;
  		
   }

    private String fetchInformationElementValue(String ieString)
    {
    	String ieValue = new String();
    	try 
	    {
  			int tagBeginIndex = inputMsgBuffer.toString().indexOf(ieString);
  			if (tagBeginIndex == -1)
  			{
  				log.info(ieString+ " Not found in the Input Buffer");
  				return null;
  			}
  			
  			int tagIDStart = inputMsgBuffer.toString().indexOf(">", tagBeginIndex);
  			int tagIDEnd =  inputMsgBuffer.toString().indexOf("</", tagIDStart);
  			
  			ieValue = inputMsgBuffer.toString().substring(tagIDStart + 1, tagIDEnd);
  			log.info("Value of " + ieString + ":" + ieValue);
  	  	
	    }
	  	catch (Exception except) {
	  		 log.error("", except);
	  	}
	  	
	  	return ieValue;
    }
    
    private boolean checkMessageType(String msgType)
    {
    	if (inputMsgBuffer.indexOf(msgType) != -1)
    		return true;
    	else
    		return false;
    }
    
    private void sendDeliveryRequestResponse(BufferedOutputStream bufWriter, String transID)
    {
        StringBuffer deliveryRspSOAPContent = new StringBuffer();
        StringBuffer deliveryRspHTTPContent = new StringBuffer();
        try
        { 
      	  deliveryRspSOAPContent.append("<?xml version='1.0' ?>\r\n");
      	  deliveryRspSOAPContent.append("<env:Envelope xmlns:env=\"http://schemas.xmlsoap.org/soap/envelope/\">\r\n");
      	  deliveryRspSOAPContent.append("<env:Header>\r\n");
      	  deliveryRspSOAPContent.append("<mm7:TransactionID xmlns:mm7=\"http://www.3gpp.org/ftp/Specs/archive/23_series/23.140/schema/REL-5-MM7-1-2\" env:mustUnderstand=\"1\">\r\n");
      	  deliveryRspSOAPContent.append(transID + "\r\n");
      	  deliveryRspSOAPContent.append("</mm7:TransactionID>\r\n");
      	  deliveryRspSOAPContent.append("</env:Header>\r\n");
      	  deliveryRspSOAPContent.append("<env:Body>\r\n");
      	  deliveryRspSOAPContent.append("<mm7:DeliverRsp xmlns=\"http://www.3gpp.org/ftp/Specs/archive/23_series/23.140/schema/REL-5-MM7-1-2\">\r\n");
      	  deliveryRspSOAPContent.append("<MM7Version>5.3.0</MM7Version>\r\n");
      	  deliveryRspSOAPContent.append("<ServiceCode>SampleServiceCode</ServiceCode>\r\n");
      	  deliveryRspSOAPContent.append("<Status>\r\n");
      	  deliveryRspSOAPContent.append("<StatusCode>1000</StatusCode>\r\n");
      	  deliveryRspSOAPContent.append("<StatusText>Success</StatusText>\r\n");
      	  deliveryRspSOAPContent.append("</Status>\r\n");
      	  deliveryRspSOAPContent.append("</mm7:DeliverRsp>\r\n");
      	  deliveryRspSOAPContent.append("</env:Body>\r\n");
      	  deliveryRspSOAPContent.append("</env:Envelope>\r\n");
      	  deliveryRspSOAPContent.append("\r\n");
  		
      	  deliveryRspHTTPContent.append("HTTP/1.0 200 OK\r\n");
      	  deliveryRspHTTPContent.append("Content-Type: text/xml; charset=\"utf-8\"");
      	  deliveryRspHTTPContent.append("Content-Length: " + deliveryRspSOAPContent.length() + "\r\n");
  		
      	  // Write the content to the socket
      	  bufWriter.write(deliveryRspHTTPContent.toString().getBytes(ISO_8859_1));
      	  bufWriter.write(deliveryRspSOAPContent.toString().getBytes(ISO_8859_1));
  		
      	  //Send the data
      	  bufWriter.flush();
      	  
      	  log.info("The Delivery Request Response sent: "+ deliveryRspHTTPContent.toString() + deliveryRspSOAPContent.toString());
        } 
        catch (Exception except) {
        	log.error("", except);
        }
  	
  		
    }

    private void sendSubmitRequest( BufferedOutputStream bufWriter, String linkedID )
    {
    	try
    	{
    		StringBuffer submitReqSOAPContent = new StringBuffer();
	        StringBuffer submitReqHTTPContent = new StringBuffer();
	         
	    	//create a new individual transaction id. use millisecond time+a static increment+threadname
	        long epochTime = new Date().getTime();
	        increment++;
	        String transId = epochTime + "-" + increment + "-" + getName().toString();
	        	
			submitReqSOAPContent.append("-----mime-boundary-F032A15B.98A2DA1C---\r\n");
			submitReqSOAPContent.append("Content-Type: text/xml; charset=utf-8\r\n");
			submitReqSOAPContent.append("Content-ID: <mm7_msg>\r\n");
			submitReqSOAPContent.append("\r\n");
			submitReqSOAPContent.append("<?xml version='1.0' ?>\r\n");
			submitReqSOAPContent.append("<env:Envelope xmlns:env=\"http://schemas.xmlsoap.org/soap/envelope/\">\r\n");
			submitReqSOAPContent.append("<env:Header>\r\n");
			submitReqSOAPContent.append("<mm7:TransactionID xmlns:mm7=\"http://www.3gpp.org/ftp/Specs/archive/23_series/23.140/schema/REL-5-MM7-1-2\" env:mustUnderstand=\"1\">\r\n");
			submitReqSOAPContent.append(transId+"\r\n");
			submitReqSOAPContent.append("</mm7:TransactionID>\r\n");
			submitReqSOAPContent.append("</env:Header>\r\n");
			submitReqSOAPContent.append("<env:Body>\r\n");
			submitReqSOAPContent.append("<SubmitReq xmlns=\"http://www.3gpp.org/ftp/Specs/archive/23_series/23.140/schema/REL-5-MM7-1-2\">\r\n");
			submitReqSOAPContent.append("<MM7Version>5.3.0</MM7Version>\r\n");
			submitReqSOAPContent.append("<SenderIdentification>\r\n");
			submitReqSOAPContent.append("<VASPID>"+mm7Parameters.vaspID + "</VASPID>\r\n"); 
			submitReqSOAPContent.append("<VASID>" + mm7Parameters.vaspID + "</VASID>\r\n");
			submitReqSOAPContent.append("</SenderIdentification>\r\n");
			submitReqSOAPContent.append("<Recipients>\r\n");
			submitReqSOAPContent.append("<To>\r\n");
			submitReqSOAPContent.append("<Number>" + mm7Parameters.recipientAddr + "</Number>\r\n");
			submitReqSOAPContent.append("</To>\r\n");
			submitReqSOAPContent.append("</Recipients>\r\n");
			submitReqSOAPContent.append("<ServiceCode>" + mm7Parameters.serviceCode + "</ServiceCode>\r\n");
			submitReqSOAPContent.append("<LinkedID>" + linkedID + "</LinkedID>\r\n");
			submitReqSOAPContent.append("<MessageClass>" + mm7Parameters.msgClass + "</MessageClass>\r\n");
			submitReqSOAPContent.append("<DeliveryReport>" + mm7Parameters.deliveryReport + "</DeliveryReport>\r\n");
			submitReqSOAPContent.append("<ReadReply>" + mm7Parameters.readReplyReport + "</ReadReply>\r\n");
			submitReqSOAPContent.append("<Priority>" + mm7Parameters.priority + "</Priority>\r\n");
			submitReqSOAPContent.append("<ChargedParty>" + mm7Parameters.chargedParty + "</ChargedParty>\r\n");
			submitReqSOAPContent.append("<Subject>" + mm7Parameters.subject + "</Subject>\r\n");
			submitReqSOAPContent.append("<Content href=\"cid:mms_cid\" />\r\n");
			submitReqSOAPContent.append("</SubmitReq>\r\n");
			submitReqSOAPContent.append("</env:Body>\r\n");
			submitReqSOAPContent.append("</env:Envelope>\r\n");
			submitReqSOAPContent.append("\r\n");
			submitReqSOAPContent.append("-----mime-boundary-F032A15B.98A2DA1C---\r\n");
			submitReqSOAPContent.append("Content-Type: multipart/mixed; boundary=\"---mime-boundary-C97CAD9D.029FABDE---\"\r\n");
			submitReqSOAPContent.append("Content-ID: <mms_cid>\r\n");
			submitReqSOAPContent.append("\r\n");
			submitReqSOAPContent.append("-----mime-boundary-C97CAD9D.029FABDE---\r\n");
			submitReqSOAPContent.append("Content-Type: text/plain\r\n");
			submitReqSOAPContent.append("Content-ID: <40F64F99.txt>\r\n");
			submitReqSOAPContent.append("Content-location: 40F64F99.txt\r\n");
			submitReqSOAPContent.append("\r\n");
			submitReqSOAPContent.append("test from jmeter, hello world!\r\n");
			submitReqSOAPContent.append("-----mime-boundary-C97CAD9D.029FABDE-----\r\n");
			submitReqSOAPContent.append("\r\n");
			submitReqSOAPContent.append("-----mime-boundary-F032A15B.98A2DA1C----- ");
			submitReqSOAPContent.append("\r\n");
	
			submitReqHTTPContent.append("POST /mm7 HTTP/1.0\r\n");
		//	submitReqHTTPContent.append( ("Authorization: Basic " + authHeaderValue + "\r\n" ) );
			submitReqHTTPContent.append("Host: "+ "jmeter.mms.com"+ "\r\n");
			submitReqHTTPContent.append("Content-Length: " + submitReqSOAPContent.length() + "\r\n");
			submitReqHTTPContent.append("Content-Type: multipart/related; boundary=\"---mime-boundary-F032A15B.98A2DA1C---\"; type=\"text/xml\"; start=\"<mm7_msg>\""+"\r\n");
			submitReqHTTPContent.append("SOAPAction: \"\"\r\n");
			submitReqHTTPContent.append("\r\n");
			
	        // add the http and xml contents buffers to the mix
			bufWriter.write(submitReqHTTPContent.toString().getBytes(ISO_8859_1));
			bufWriter.write(submitReqSOAPContent.toString().getBytes(ISO_8859_1));
	        
			//Send data
			bufWriter.flush();
			
			 log.info("The Submit Request sent: "+ submitReqHTTPContent.toString() + submitReqSOAPContent.toString());
    	}
    	catch(Exception e)
    	{
    		log.error("", e);
    	}
    }
}
